#pragma once

#include <iostream>
#include <sys/epoll.h>
#include <cstring>
#include <unistd.h>

#include "err.hpp"
#include "log.hpp"
#include "Socket.hpp"

static const int defultListenSize = 128;
class Epoller
{
public:
    Epoller():_epfd(defaultSock)
    {}
    ~Epoller()
    {
        if(_epfd != defaultSock) close(_epfd);
    }
public:
    //创建epoll模型
    void Creat()
    {
        _epfd = epoll_create(defultListenSize);
        if(_epfd < 0)
        {
            logMessage(FATAL,"epoll_creat err,errno:%d,errstr:%s",errno,strerror(errno));
            exit(EPOLL_CREATE_ERR);
        }
    }

    //添加监听的套接字与事件，注：et模式下的sock要非阻塞
    bool AddEvent(int sock,uint32_t event)
    {
        //填写事件结构体
        struct epoll_event addEvent;
        addEvent.events = event;
        addEvent.data.fd = sock;
        //添加
        int ret = epoll_ctl(_epfd,EPOLL_CTL_ADD,sock,&addEvent);
        return ret == 0;//返回值为0添加成功
    }

    //修改与删除    注：也可以像上面的添加一样，将2种操作分离
    bool Control(int sock,int act,uint32_t event)
    {
        int ret = -1;
        if(act == EPOLL_CTL_MOD)
        {
            //填写修改新事件结构体
            struct epoll_event newEvent;
            newEvent.events = event;
            newEvent.data.fd = sock;
            ret = epoll_ctl(_epfd,EPOLL_CTL_MOD,sock,&newEvent);
        }
        else if(act == EPOLL_CTL_DEL)
        {
            //删除
            ret = epoll_ctl(_epfd,EPOLL_CTL_DEL,sock,nullptr);
        }   
        else if(act == EPOLL_CTL_ADD)
        {
            AddEvent(sock,event);
        }
        else
        {
            logMessage(ERROR,"Illegal input parameter");
            return false;
        }

        return ret == 0;
    }
    //检查（等待）是否有eopll模型中的监听事件已就绪
    int Wait(struct epoll_event reves[],int revesNum,int timeout)
    {
        int readyNum = epoll_wait(_epfd,reves,revesNum,timeout);
        return readyNum;
    } 

    void Close()
    {
        if(_epfd != defaultSock)close(_epfd);
    }
private:
    int _epfd;
};